/*
 * @Author: wanghan
 * @Date: 2021-05-17 10:47:59
 * @LastEditors: 黄威
 * @LastEditTime: 2022-02-17 15:44:33
 * @Description: 添加三维独有的地图服务相关方法和接口
 */
import type { CesiumServiceType } from 'types'

import * as Cesium from 'Cesium'
import { Viewer } from '@/utils/view'
import { parseServiceUrl } from '@/utils/service-creator'

import { Component, Vue } from 'vue-property-decorator'

@Component
export default class CLayerMixin extends Vue {
    map!: Viewer

    terrainProvider?: Cesium.TerrainProvider
    hashSceneLayers: { [key: string]: any } = {}

    /**
     * @public
     * 添加三维地图服务
     * @param {String} lyrId 图层id
     * @param {String} svcType 服务类型
     * @param {String} svcUrl 服务地址
     * @param {any?} props 服务元数据（不一定需要）
     * @returns 三维服务对象（地形 或 3dTiles场景）
     */
    async addC3Service(
        lyrId: string,
        svcType: CesiumServiceType,
        svcUrl: string,
        props?: any
    ): Promise<any> {
        // 地形服务
        if (/(smterrain)|(^0$)/i.test(svcType)) {
            const terrainProvider = this.addTerrain(svcUrl, props)
            ;(terrainProvider as any).__layerId = lyrId
            return terrainProvider
        }
        // 3dTiles服务
        else if (/(3dtiles)|(^5$)/i.test(svcType)) {
            // todo
            return
        }
        // s3m服务类型
        else if (/(sms3mlayers)|(^6$)/i.test(svcType)) {
            return this.addScene(lyrId, svcUrl, props)
        }
    }

    /**
     * @public
     * 移除三维地图服务
     * @param {String} lyrId 服务id
     */
    removeC3Service(lyrId: string) {
        if (
            this.terrainProvider &&
            (this.terrainProvider as any).__layerId === lyrId
        ) {
            this.removeTerrain()
        } else {
            this.removeScene(lyrId)
        }
    }

    /**
     * @public
     * 添加地形
     * @param terUrl 地形地址
     * @param props 地形参数
     */
    addTerrain(terUrl: string, props?: any): Cesium.TerrainProvider {
        this.terrainProvider = new Cesium.CesiumTerrainProvider({
            url: parseServiceUrl(terUrl),
            isSct: true,
            ...props,
        })
        this.map.terrainProvider = this.terrainProvider

        return this.terrainProvider
    }

    /**
     * @public
     * 移除地形
     */
    removeTerrain() {
        if (this.terrainProvider) {
            this.map.terrainProvider = new Cesium.EllipsoidTerrainProvider({})
            this.terrainProvider = undefined
        }
    }

    /**
     * @public
     * 添加场景
     * @param sceneId id
     * @param sceneUrl 路径地址
     * @param obj 配置
     */
    async addScene(
        sceneId: string,
        sceneUrl: string,
        props?: any
    ): Promise<any> {
        const scene = this.map.scene
        props = { autoSetView: false, ...props }

        return new Promise((resolve, reject) => {
            try {
                //添加场景
                const promise = (scene as any).open(
                    parseServiceUrl(sceneUrl),
                    (props && props.sceneName) || undefined, //工作空间中有多个场景，需要指定场景名称；设置为undefined，默认打开第一个
                    props
                )
                Cesium.when(promise, layer => {
                    this.$set(this.hashSceneLayers, sceneId, layer)

                    layer.__layerId = sceneId
                    layer.__layerType = 'service'
                    resolve(layer)
                })
            } catch (error) {
                reject(error)
            }
        })
    }

    /**
     * @public
     * 添加倾斜摄影
     * @param tilesId id
     * @param tilesUrl 路径地址
     * @param obj 配置
     */
    async addTilesLayer(
        tilesId: string,
        tilesUrl: string,
        obj: any
    ): Promise<any> {
        const scene = this.map.scene

        return new Promise((resolve, reject) => {
            try {
                //添加倾斜摄影
                const promise = (scene as any).addS3MTilesLayerByScp(
                    parseServiceUrl(tilesUrl),
                    { name: tilesId }
                )
                Cesium.when(promise, layer => {
                    this.$set(this.hashSceneLayers, layer.name, layer)

                    //可见高度 单位米
                    if (obj.visibleDistance) {
                        layer.visibleDistanceMax = parseInt(obj.visibleDistance)
                    }
                    // 倾斜摄影抬高 单位米
                    if (obj.bottomAltitude) {
                        const style3D = new (Cesium as any).Style3D()
                        style3D.bottomAltitude = parseInt(obj.bottomAltitude)
                        layer.style3D = style3D
                        layer.refresh()
                    }
                    // 是否定位
                    if (obj.toPosition) {
                        this.map.camera.flyTo({
                            destination: Cesium.Cartesian3.fromDegrees(
                                layer.lon,
                                layer.lat,
                                layer.visibleDistanceMax
                            ),
                            orientation: {
                                heading: Cesium.Math.toRadians(0),
                                pitch: Cesium.Math.toRadians(-90),
                            },
                        } as any)
                    }

                    layer.__layerId = tilesId
                    layer.__layerType = 'service'
                    resolve(layer)
                })
            } catch (err) {
                reject(err)
            }
        })
    }

    /**
     * @public
     * 移除地形
     */
    removeScene(sceneId: string) {
        let layer = this.hashSceneLayers[sceneId]
        if (!layer) return

        if (!Array.isArray(layer)) layer = [layer]
        layer.forEach((l: any) =>
            (this.map.scene as any).layers.remove(l.name, true)
        )

        this.$delete(this.hashSceneLayers, sceneId)
    }
}
